# -*- coding: utf-8 -*-
import math
import sys

from PyQt5.QtCore import Qt, QRectF
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class HorizontalMeter(QWidget):
    def __init__(self, *args, **kwargs):
        text = kwargs.pop("text", "")
        super(HorizontalMeter, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        # 背景区域设置
        self.bgWidth = 200  # 控件显示区宽度
        self.bgHeight = 80  # 控件显示区高度
        self.bgColor = QColor(55, 55, 55, 100)  # 背景色
        self.bgBorderColor = QColor(200, 200, 200, 200)  # 边框颜色

        # 条形色块绘制
        self.region1Color = QColor(200, 200, 200, 0)  #
        self.region2Color = QColor(0, 255, 0, 0)  #
        self.region3Color = QColor(255, 0, 0, 0)  #
        self.region2MinValue = 0  # 20以下以region1Color显示
        self.region2MaxValue = 180  # 50以上以region3Color显示
        self.lateralDirection = 0  # 0-色块在上方 1-色块在下方
        self.ColorBarWidthRatio = 0.1  # 条形色块宽度占据比例
        self.startRegionRatio = 0.05  # 区块1占据比例
        self.midRegionRatio = 0.8  # 区块2占据比例
        self.endRegionRatio = 0.15  # 区块3占据比例

        # 指针滑块属性
        self.pointerColor = QColor(0, 0, 0, 0)  # 指针背景色
        self.pointerBorderColor = QColor(19, 133, 53, 255)  # 指针背景色
        self.pointerWidthRatio = 0.06  # 指针宽度 0 ~ 1
        self.pointerHeightRatio = 0.5  # 指针高度 0 ~ 1
        self.pointerOffsetX = 0  # X轴偏移 向右为正 0~1
        self.pointerOffsetY = 0  # Y轴偏移 向上为正 0~1
        # 目标滑块属性
        self.targetColor = QColor(248, 161, 164, 255)  # 指针背景色
        self.targetBorderColor = QColor(19, 133, 53, 0)  # 指针背景色
        self.targetWidthRatio = 0.07  # 指针宽度 0 ~ 1
        self.targetHeightRatio = 0.15  # 指针高度 0 ~ 1
        self.targetOffsetX = 0  # X轴偏移 向右为正 0~1
        self.targetOffsetY = 0  # Y轴偏移 向上为正 0~1
        self.targetValue = 100
        # 设置字符
        self.font = QFont("Noto Sans S Chinese Bold", 12)  # 读数文字字体
        # self.font.setBold(True)
        self.pointerTextColor = QColor(255, 255, 255, 255)  # 刻度值文字显示颜色

        # 刻度尺属性
        self.currentValue = 0  # 当前标识值
        self.scaleColor = QColor(255, 255, 255, 255)  # 刻度线颜色
        self.scaleLineWidth = 1  # 刻度线宽
        self.scaleFont = QFont("Noto Sans S Chinese Bold", 12)  # 读数文字字体
        self.scaleLineStartPos = 0.8  # 刻度线起始位置（0 ~ 1）
        self.scaleLineEndPos = 1  # 刻度线终止位置（0 ~ 1）
        self.scaleUnit = 2  # 刻度单位 刻度线之间的间隔值

        self.viewLength = 10  # 可见区域长度
        self.startValue = self.currentValue - self.viewLength / 2  # 起始位置对应取值
        self.endValue = self.startValue + self.viewLength  # 终止位置对应取值

        # 精细刻度标尺属性
        self.fineScaleUnit = 1  # 细值刻度单位
        self.fineScaleColor = QColor(255, 255, 255, 255)  # 刻度线颜色
        self.fineScaleLineWidth = 0.5  # 刻度线宽
        self.fineScaleLineStartPos = 0.85  # 刻度线起始位置（0 ~ 1）
        self.fineScaleLineEndPos = 1  # 刻度线终止位置（0 ~ 1）

        self.maxValue = 500  # 最大值 标尺显示最大值 随着当前取值和视角宽度变动
        self.minValue = 0  # 最小值 标尺显示最小值

        self.setMinimumSize(self.bgWidth, self.bgHeight)

    # 设置取值接口
    def setValue(self, value):
        self.currentValue = value
        self.startValue = self.currentValue - self.viewLength / 2  # 起始位置对应取值
        self.endValue = self.startValue + self.viewLength  # 终止位置对应取值
        self.update()

    def setTargetValue(self, value):
        self.targetValue = value
        self.update()

    def paintEvent(self, event):
        width = self.width()
        height = self.height()
        # print(width)
        # print(height)
        painter = QPainter(self)  # 初始化painter
        painter.translate(width / 2, height / 2)  # 坐标轴变换，调用translate()将坐标原点平移至窗口中心

        # 坐标刻度自适应
        # side = min(width, height)
        # painter.scale(side / self.bgWidth, side / self.bgWidth)
        self.bgWidth = width
        self.bgHeight = height
        # 本项目中将坐标缩小为side/200倍，即画出length=10的直线，其实际长度应为10*(side/200)。
        painter.setClipRect(QRectF(-self.bgWidth / 2, -self.bgHeight / 2, self.bgWidth, self.bgHeight),
                            Qt.IntersectClip)
        # 启用反锯齿，使画出的曲线更平滑
        painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)
        painter.begin(self)

        # 开始画图
        self.drawBackGround(painter)
        self.drawColorBar(painter)
        self.drawFineScaleLine(painter)
        self.drawScaleLine(painter)
        self.drawTargetIndicator(painter)
        self.drawPointerIndicator(painter)

        painter.end()

    def drawBackGround(self, painter):  # 背景区域绘制
        painter.save()
        painter.setPen(Qt.NoPen)
        brush = QBrush(Qt.SolidPattern)
        brush.setColor(self.bgColor)
        painter.setBrush(brush)
        painter.drawRect(-self.bgWidth / 2, -self.bgHeight / 2, self.bgWidth, self.bgHeight)

        pen = QPen(Qt.blue, 1, Qt.SolidLine)
        pen.setColor(self.bgBorderColor)
        painter.setPen(pen)
        painter.drawLine(-self.bgWidth / 2, -self.bgHeight / 2, self.bgWidth / 2, -self.bgHeight / 2)
        painter.drawLine(self.bgWidth / 2, -self.bgHeight / 2, self.bgWidth / 2, self.bgHeight / 2)
        painter.drawLine(self.bgWidth / 2, self.bgHeight / 2, -self.bgWidth / 2, self.bgHeight / 2)
        painter.drawLine(-self.bgWidth / 2, self.bgHeight / 2, -self.bgWidth / 2, -self.bgHeight / 2)

    def drawColorBar(self, painter):  # 条形区域绘制
        painter.save()  # save()保存当前坐标系
        painter.setPen(Qt.NoPen)
        totallen = self.bgWidth

        if self.region2MinValue > self.startValue:  # 第一区域色块长度
            region1_len = (self.region2MinValue - self.startValue) / self.viewLength * totallen
            region1_len = min(totallen, region1_len)
        else:
            region1_len = 0

        if self.region2MaxValue < self.endValue:  # 第三区域色块长度
            region3_len = (self.endValue - self.region2MaxValue) / self.viewLength * totallen
            region3_len = min(totallen, region3_len)
        else:
            region3_len = 0

        region2_len = totallen - region3_len - region1_len  # 第二区域色块长度

        rg = QLinearGradient(0, self.bgHeight / 2, 0, -self.bgHeight / 2)
        ratio = 1 - self.ColorBarWidthRatio

        # 绘制底部色块
        # 设置渐变色
        if self.lateralDirection < 1:
            rg.setColorAt(0, Qt.transparent)  # 透明色
            rg.setColorAt(ratio, Qt.transparent)
            rg.setColorAt(ratio + 0.02, self.region1Color)
            rg.setColorAt(1, self.region1Color)
        else:
            rg.setColorAt(0, self.region1Color)  # 透明色
            rg.setColorAt(1 - ratio, self.region1Color)
            rg.setColorAt(1 - ratio + 0.02, Qt.transparent)
            rg.setColorAt(1, Qt.transparent)
        # 绘制矩形
        painter.setBrush(rg)
        painter.drawRect(-self.bgWidth / 2, -self.bgHeight / 2, self.bgWidth, self.bgHeight)

        # # 绘制中间色块
        # 设置渐变色
        if self.lateralDirection < 1:
            rg.setColorAt(0, Qt.transparent)  # 透明色
            rg.setColorAt(ratio, Qt.transparent)
            rg.setColorAt(ratio + 0.02, self.region2Color)
            rg.setColorAt(1, self.region2Color)
        else:
            rg.setColorAt(0, self.region2Color)  # 透明色
            rg.setColorAt(1 - ratio, self.region2Color)
            rg.setColorAt(1 - ratio + 0.02, Qt.transparent)
            rg.setColorAt(1, Qt.transparent)
        # 绘制矩形
        painter.setBrush(rg)
        painter.drawRect(-self.bgWidth / 2 + region1_len, -self.bgHeight / 2, self.bgWidth,
                         self.bgHeight)
        # 绘制最上层色块
        # 设置渐变色
        if self.lateralDirection < 1:
            rg.setColorAt(0, Qt.transparent)  # 透明色
            rg.setColorAt(ratio, Qt.transparent)
            rg.setColorAt(ratio + 0.02, self.region3Color)
            rg.setColorAt(1, self.region3Color)
        else:
            rg.setColorAt(0, self.region3Color)  # 透明色
            rg.setColorAt(1 - ratio, self.region3Color)
            rg.setColorAt(1 - ratio + 0.02, Qt.transparent)
            rg.setColorAt(1, Qt.transparent)
        # 绘制矩形
        painter.setBrush(rg)
        painter.drawRect(-self.bgWidth / 2 + region1_len + region2_len, -self.bgHeight / 2,
                         self.bgWidth,
                         self.bgHeight)
        painter.restore()  # restore()恢复坐标系

    def drawPointerIndicator(self, painter):
        painter.save()
        pen = QPen(self.pointerBorderColor, 4, Qt.SolidLine)
        painter.setPen(pen)
        painter.setBrush(self.pointerColor)

        # 绘制指针
        pointer_width = self.pointerWidthRatio * self.bgWidth
        pointer_height = self.pointerHeightRatio * self.bgHeight
        pointer_offset_x = self.pointerOffsetX * self.bgWidth  # X轴偏移 向右为正
        pointer_offset_y = (0.5 - self.pointerHeightRatio + self.pointerOffsetY) * self.bgHeight  # Y轴偏移 向上为正
        # 绘制多边形做指针
        pts = QPolygon()

        if self.lateralDirection < 1:
            #               /\(0, -height)
            #              /  \
            # (-width/2,-height/2) /    \  (widht/2, -height/2)
            #             \    /
            #              \  /
            #               \/ (0,0)
            pts.setPoints(0, 0,
                          pointer_width / 2, -pointer_height / 2,
                          0, -pointer_height,
                          -pointer_width / 2, -pointer_height / 2)
            painter.translate(pointer_offset_x, -pointer_offset_y)
        else:
            #               /\(0, 0)
            #              /  \
            # (-width/2, height/2) /    \  (widht/2, height/2)
            #             \    /
            #              \  /
            #               \/ (0,height)
            pts.setPoints(0, 0,
                          -pointer_width / 2, pointer_height / 2,
                          0, pointer_height,
                          pointer_width / 2, pointer_height / 2)
            painter.translate(pointer_offset_x, pointer_offset_y)

        painter.drawConvexPolygon(pts)

        # painter.translate(pointer_offset_x, 0)  # 坐标回到中心点
        # painter.setFont(self.font)
        # painter.setPen(self.pointerTextColor)  # 设置文字颜色
        # strValue = '%3d' % int(self.currentValue)
        # textWidth = self.fontMetrics().width("%3d" % int(self.maxValue)) * 1.5
        #
        # # 显示当前刻度值
        # if self.lateralDirection < 1:
        #     # 指向右侧
        #     rectf = QRectF(-pointer_offset_x, -pointer_height / 2, pointer_width, pointer_height)
        # else:
        #     # 指向左侧
        #     rectf = QRectF(textWidth - pointer_width, -pointer_height / 2, pointer_width, pointer_height)
        #
        # painter.drawText(rectf, Qt.AlignVCenter | Qt.AlignCenter, strValue)
        painter.restore()

    def drawTargetIndicator(self, painter):
        painter.save()
        pen = QPen(self.targetBorderColor, 1, Qt.SolidLine)
        painter.setPen(pen)
        painter.setBrush(self.targetColor)

        # 绘制指针
        pointer_width = self.targetWidthRatio * self.bgWidth
        pointer_height = self.targetHeightRatio * self.bgHeight
        tmp_targetValue = self.targetValue
        tmp_targetDiffValue = tmp_targetValue - self.currentValue  # 当前值和目标值之差
        if tmp_targetDiffValue < -self.viewLength:
            tmp_targetDiffValue = tmp_targetDiffValue + 360
        if tmp_targetDiffValue > self.viewLength:
            tmp_targetDiffValue = tmp_targetDiffValue - 360

        pointer_offset_x = (self.targetOffsetX +
                            tmp_targetDiffValue / self.viewLength) * self.bgWidth  # X轴偏移 向右为正
        pointer_offset_y = (0.5 - self.targetHeightRatio + self.targetOffsetY) * self.bgHeight  # Y轴偏移 向上为正

        # 绘制多边形做指针
        pts = QPolygon()

        tan_sharpness_agl = math.tan(math.radians(30))

        # print(tanSharpnessAgl)
        if self.lateralDirection < 1:
            pts.setPoints(0, -tan_sharpness_agl / 2 * pointer_width,
                          pointer_width / 2, 0,
                          pointer_width / 2, -pointer_height,
                          -pointer_width / 2, -pointer_height,
                          -pointer_width / 2, 0)
            painter.translate(pointer_offset_x, -pointer_offset_y)
        else:
            pts.setPoints(0, tan_sharpness_agl / 2 * pointer_width,
                          pointer_width / 2, 0,
                          pointer_width / 2, pointer_height,
                          -pointer_width / 2, pointer_height,
                          -pointer_width / 2, 0)
            painter.translate(pointer_offset_x, pointer_offset_y)

        painter.drawConvexPolygon(pts)
        painter.restore()

    def drawScaleLine(self, painter):  # 画出刻度和刻度文字
        painter.save()
        # 绘制刻度线
        totalheight = self.bgHeight
        totallen = self.bgWidth
        unit = self.scaleUnit
        startpos = self.scaleLineStartPos
        endpos = self.scaleLineEndPos
        # 计算从最低点开始第一个刻度所对应的取值
        if self.lateralDirection < 1:
            start_offset = (0.5 - startpos) * totalheight
            end_offset = (0.5 - endpos) * totalheight
        else:
            start_offset = (startpos - 0.5) * totalheight
            end_offset = (endpos - 0.5) * totalheight

        text_width = self.fontMetrics().width("%3d" % int(self.maxValue)) * 1.5
        text_height = self.fontMetrics().height()
        painter.setFont(self.scaleFont)

        tmp_scale_value = (int(self.startValue / unit) - 1) * unit
        while tmp_scale_value < self.endValue + unit:
            # 画刻度线
            painter.setPen(QPen(self.scaleColor, self.scaleLineWidth, Qt.SolidLine))
            pos = -totallen / 2 + (tmp_scale_value - self.startValue) / self.viewLength * totallen
            painter.drawLine(pos, start_offset, pos, end_offset)  # 画出刻度线

            painter.setPen(self.pointerTextColor)  # 设置文字颜色
            # 画刻度文字
            tmp_val = tmp_scale_value
            if tmp_val < 0:
                tmp_val = tmp_val + 360
            if tmp_val >= 360:
                tmp_val = tmp_val - 360

            str_value = "%3d" % int(tmp_val)
            if self.lateralDirection < 1:
                rectf = QRectF(pos - text_width / 2, start_offset, text_width, text_height * 1.1)
                painter.drawText(rectf, Qt.AlignVCenter | Qt.AlignCenter, str_value)
            else:
                rectf = QRectF(pos, 0, text_width, text_height * 1.1)
                painter.drawText(rectf, Qt.AlignVCenter | Qt.AlignCenter, str_value)

            tmp_scale_value = tmp_scale_value + unit

        painter.restore()

    def drawFineScaleLine(self, painter):  # 画出刻度和刻度文字
        painter.save()
        # 绘制刻度线
        totalheight = self.bgHeight
        totallen = self.bgWidth
        unit = self.fineScaleUnit
        startpos = self.fineScaleLineStartPos
        endpos = self.fineScaleLineEndPos
        # 计算从最低点开始第一个刻度所对应的取值
        if self.lateralDirection < 1:
            start_offset = (0.5 - startpos) * totalheight
            end_offset = (0.5 - endpos) * totalheight
        else:
            start_offset = (startpos - 0.5) * totalheight
            end_offset = (endpos - 0.5) * totalheight

        text_width = self.fontMetrics().width("%3d" % int(self.maxValue)) * 1.5
        text_height = self.fontMetrics().height()
        # painter.setFont(self.fineScaleFont)

        tmp_scale_value = (int(self.startValue / unit) - 1) * unit
        while tmp_scale_value < self.endValue + unit:
            # 画刻度线
            painter.setPen(QPen(self.fineScaleColor, self.fineScaleLineWidth, Qt.SolidLine))
            pos = -totallen / 2 + (tmp_scale_value - self.startValue) / self.viewLength * totallen
            painter.drawLine(pos, start_offset, pos, end_offset)  # 画出刻度线

            painter.setPen(self.pointerTextColor)  # 设置文字颜色

            tmp_scale_value = tmp_scale_value + unit

        painter.restore()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = HorizontalMeter()
    # demo.InitUI()
    demo.show()
    demo.setValue(88)  # 设置指针指向
    demo.setTargetValue(88.5)

    # demo.setValue(200)
    # demo.setTitle("Title_____")  # 设置图标题
    sys.exit(app.exec_())
